#include "HCSR04.h"

volatile uint32_t start_time = 0, end_time = 0;
volatile uint8_t measure_status = 0; // 0:空闲 1:测量中 2:完成 3:错误

void SR04_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // GPIO初始化
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    // Trig引脚
    GPIO_InitStructure.GPIO_Pin = TRIG_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TRIG_PORT, &GPIO_InitStructure);

    // Echo引脚
    GPIO_InitStructure.GPIO_Pin = ECHO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(ECHO_PORT, &GPIO_InitStructure);

    // 外部中断配置
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // NVIC配置
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 定时器配置(1us计数)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 65535;
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    TIM_Cmd(TIM4, ENABLE);
}

void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) != RESET)
    {
        if (measure_status == 1)
        { // 只有在测量中才处理
            if (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET)
            {
                // 上升沿
                start_time = TIM4->CNT;
            }
            else
            {
                // 下降沿
                end_time = TIM4->CNT;
                uint32_t time_diff;

                // 计算时间差(处理定时器溢出)
                if (end_time >= start_time)
                {
                    time_diff = end_time - start_time;
                }
                else
                {
                    time_diff = (65535 - start_time) + end_time;
                }

                // 数据有效性检查(2cm-400cm)
                if (start_time != 0 && end_time != 0)
                {
                    if (time_diff >= 117 && time_diff <= (MAX_DISTANCE_CM * 58))
                    {
                        measure_status = 2; // 测量完成
                    }
                    else
                    {
                        measure_status = 3; // 数据错误
                    }
                }
            }
        }
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

// 阻塞式测量函数
float SR04_MeasureDistance(void)
{
    uint32_t start_tick = TIM4->CNT; // 记录开始时刻
    uint32_t timeout = TIMEOUT_US;   // 超时时间(us)

    measure_status = 1;

    // 发送触发信号（确保严格的10us脉冲）
    GPIO_SetBits(TRIG_PORT, TRIG_PIN);
    __disable_irq();
    Delay_us(10);
    __enable_irq();
    GPIO_ResetBits(TRIG_PORT, TRIG_PIN);

    // 修正后的超时检测
    while (measure_status == 1)
    {
        uint32_t current_tick = TIM4->CNT;
        uint32_t elapsed;

        // 计算经过的时间（处理计数器溢出）
        if (current_tick >= start_tick)
        {
            elapsed = current_tick - start_tick;
        }
        else
        {
            elapsed = (0xFFFF - start_tick) + current_tick + 1;
        }

        if (elapsed >= timeout)
        {
            measure_status = 3; // 超时
            break;
        }
    }

    if (measure_status == 2)
    { // 测量成功
        uint32_t time_diff = (end_time >= start_time) ? (end_time - start_time) : (65535 - start_time + end_time);
        return time_diff * 0.034f / 2.0f; // 返回距离(cm)
    }

    return -1.0f; // 测量失败
}
